# -*- coding: utf-8 -*-
"""
Created on Mon Nov 20 20:18:26 2019

@author: XCL01
"""

import numpy as np
from sklearn import datasets
from sklearn.metrics import accuracy_score

#加载样本数据
np.random.seed(0)
digits = datasets.load_digits()

#生成NN模型
class NN_Model:
    epsilon = 0.01               # 学习速率
    n_epoch = 1000               # 迭代次数
    
nn = NN_Model()
train_data = np.copy(digits.data[0:100])  #取100个样本
train_label = np.copy(digits.target[0:100])
test_data = np.copy(digits.data[100:164])
test_label = np.copy(digits.target[100:164])  
nn.input_dim = np.shape(train_data)[1]  #输入层为64
nn.hide_dim = 128  #隐藏层为128
nn.output_dim = 10  #输出层为10
nn.label = np.zeros((np.shape(train_data)[0], 10))
for i in range(10):  
    nn.label[np.where(train_label == i), i] = 1
nn.W1 = np.random.randn(nn.input_dim, nn.hide_dim)/np.sqrt(nn.input_dim)  
nn.W2 = np.random.randn(nn.hide_dim, nn.output_dim)/np.sqrt(nn.hide_dim)  
nn.b1 = np.zeros((1, nn.hide_dim))  
nn.b2 = np.zeros((1, nn.output_dim))

#定义sigmod及其导数函数
def sigmod(X):  
    return 1.0 / (1 + np.exp(-X))


def sigmod_derivative(X):
    return sigmod(X) * (1 - sigmod(X))

# 正向计算
def forward(n, X):  
    n.z1 = sigmod(X.dot(n.W1) + n.b1)
    n.z2 = sigmod(n.z1.dot(n.W2) + n.b2)
    return n

#反向传播法
def back_propagation(n, X):  
    for i in range(n.n_epoch):
        forward(n, X)
        L = np.sum((n.z2 - n.label)**2)
        y_pred = np.argmax(n.z2, axis=1)
        accuracy = accuracy_score(train_label, y_pred)
        print("epoch [%4d] L = %f, accuracy = %f" % (i, L, accuracy))
        
        #更新权值
        d2 = n.z2 * (1 - n.z2) * (n.label - n.z2)
        d1 = n.z1 * (1 - n.z1) * np.dot(d2, n.W2.T)
        n.W2 += n.epsilon * np.dot(n.z1.T, d2)
        n.b2 += n.epsilon * np.sum(d2, axis=0)
        n.W1 += n.epsilon * np.dot(X.T, d1)
        n.b1 += n.epsilon * np.sum(d1, axis=0)
        
back_propagation(nn, train_data)
forward(nn,test_data)  
pre_t = np.argmax(nn.z2, axis=1)
accuracy = accuracy_score(test_label, pre_t) 
for i in range(64):
    print("sample={},prediction= {}".format(test_label[i], pre_t[i]))
print("predict accuracy:%f" % accuracy)